package com.syh.jn.scm.domain.downstream.entity.finance;

import cn.redscarf.commons.util.bean.ExtBeanUtils;
import cn.redscarf.commons.util.exception.IllegalParameterException;
import cn.redscarf.commons.util.other.ExtAssert;
import cn.redscarf.commons.spring.SpringContextUtils;
import cn.redscarf.commons.util.validator.ValidationUtils;
import com.syh.core.ddd.domain.AbstractSimpleEntityObject;
import com.syh.jn.scm.domain.downstream.entity.purchase.DownPurchaseOrder;
import com.syh.jn.scm.domain.downstream.entity.purchase.DownPurchaseReturnOrder;
import com.syh.jn.scm.domain.downstream.repository.finance.DownCostBillReadRepository;
import com.syh.jn.scm.domain.downstream.repository.finance.DownCostBillRepository;
import com.syh.jn.scm.domain.downstream.repository.finance.DownIncomeBillReadRepository;
import com.syh.jn.scm.domain.downstream.repository.finance.DownIncomeBillRepository;
import com.syh.jn.scm.domain.downstream.repository.purchase.DownPurchaseOrderReadRepository;
import com.syh.jn.scm.domain.downstream.repository.purchase.DownPurchaseOrderRepository;
import com.syh.jn.scm.domain.downstream.repository.purchase.DownPurchaseReturnOrderReadRepository;
import com.syh.jn.scm.domain.downstream.repository.purchase.DownPurchaseReturnOrderRepository;
import com.syh.jn.scm.dto.downstream.finance.DownStatementAccountBillMto;
import com.syh.jn.scm.dto.downstream.finance.DownStatementAccountBillSto.DownStatementAccountBillItemSto;
import com.syh.jn.scm.exception.BusinessException;
import com.syh.jn.scm.service.api.downstream.finance.enums.DownCostBillEnum;
import com.syh.jn.scm.service.api.downstream.finance.enums.DownIncomeBillEnum;
import com.syh.jn.scm.service.api.downstream.finance.enums.DownStatementAccountBillEnum;
import com.syh.jn.scm.service.api.downstream.purchase.enums.DownPurchaseOrderEnums;
import com.syh.jn.scm.service.api.downstream.purchase.enums.DownPurchaseReturnOrderEnums;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;

import java.math.BigDecimal;
import java.util.UUID;

/**
 * 账单项
 */
@Data
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class DownStatementAccountBillItem extends AbstractSimpleEntityObject<Long> {

  /**
   * 生成对账单项 每张单的数据逻辑校验分配给每个项在创建的时候自己去匹配 达到职责分离
   *
   * @param sto
   * @param customerId
   */
  DownStatementAccountBillItem(DownStatementAccountBillItemSto sto, Long customerId) {
    ValidationUtils.validate(sto);
    ExtBeanUtils.copyProperties(sto, this);
    this.setUuid(UUID.randomUUID().toString());
    this.createdItemTotalAmount(customerId, false);
  }

  /**
   * 生成对账单项 每张单的数据逻辑校验分配给每个项在创建的时候自己去匹配 达到职责分离
   * @param mto
   * @param customerId
   */
  DownStatementAccountBillItem(DownStatementAccountBillMto.DownStatementAccountBillItemMto mto, Long customerId){
    ValidationUtils.validate(mto);
    ExtBeanUtils.copyProperties(mto, this);
    this.setUuid(UUID.randomUUID().toString());
    this.createdItemTotalAmount(customerId, true);
  }

  private void createdItemTotalAmount(Long customerId, boolean isUpdata) {
    switch (this.sourceType.intValue()) {
      case 0:
        DownPurchaseOrder purchaseOrder = this.getPurchaseOrd(customerId, isUpdata);
        this.totalAmount = purchaseOrder.getTotalOutAmount();
        break;
      case 1:
        DownPurchaseReturnOrder purchaseReturnOrder = this.getPurchaseReturnOrd(customerId, isUpdata);
        this.totalAmount = purchaseReturnOrder.getReturnTotalInAmount();
        break;
      case 4:
        DownIncomeBill incomeBill = this.getIncomeBill(customerId, isUpdata);
        this.totalAmount = incomeBill.getPrice();
        break;
      case 5:
        DownCostBill costBill = this.getCostBill(customerId, isUpdata);
        this.totalAmount = costBill.getPrice();
        break;
    }
    // 出现为空的情况只有单据类型与客户类型没对上 或者原始单据金额就发生错误了
    if (this.totalAmount == null) {
      throw new IllegalParameterException("非法参数，可能传入与供应商对账有销售单数据");
    }
  }

  /**
   * 处理采购订单
   * @param customerId
   * @param isUpdata
   * @return
   */
  private DownPurchaseOrder getPurchaseOrd(Long customerId, boolean isUpdata) {
    ExtAssert.isTrue(this.sourceType == DownStatementAccountBillEnum.SOURCE_PURCHASE_ORD.getStatus(), "类型错误");
    DownPurchaseOrderReadRepository purchaseOrderReadRepository = (DownPurchaseOrderReadRepository) SpringContextUtils.getBean(DownPurchaseOrderRepository.class);
    DownPurchaseOrder purchaseOrder = purchaseOrderReadRepository.getById(this.sourceId);
    ExtAssert.isTrue(purchaseOrder.getDownStreamCompanyId().equals(customerId), purchaseOrder.getCode() + "，单据归属错误！");

    if (isUpdata) {
      if (purchaseOrder.getOrdState() != DownPurchaseOrderEnums.OrdState.CONFIRM.getStatus()
              && purchaseOrder.getOrdState() != DownPurchaseOrderEnums.OrdState.STATEMENT.getStatus() ) {
        throw new BusinessException(purchaseOrder.getCode() + "，单据未在确认状态或未生成对账单！");
      }
    }
    else {
      if (purchaseOrder.getOrdState() != DownPurchaseOrderEnums.OrdState.CONFIRM.getStatus()) {
        throw new BusinessException(purchaseOrder.getCode() + "，单据未在确认状态！");
      }
      if (purchaseOrder.getStatementId() != null) {
        throw new BusinessException(purchaseOrder.getCode() + "，单据已经生成对账单！");
      }
    }

    if (!purchaseOrder.getCode().equals(this.sourceCode)) {
      throw new IllegalParameterException("单据编号与id无法对齐");
    }
    return purchaseOrder;
  }

  /**
   * 处理采购退货单
   * @param customerId
   * @param isUpdata
   * @return
   */
  private DownPurchaseReturnOrder getPurchaseReturnOrd(Long customerId, boolean isUpdata) {
    ExtAssert.isTrue(this.sourceType == DownStatementAccountBillEnum.SOURCE_PURCHASE_RETURN_ORD.getStatus(), "类型错误");
    DownPurchaseReturnOrderReadRepository purReturnOrderReadRepository = (DownPurchaseReturnOrderReadRepository) SpringContextUtils.getBean(DownPurchaseReturnOrderRepository.class);
    DownPurchaseReturnOrder purchaseReturnOrder = purReturnOrderReadRepository.getById(this.sourceId);
    ExtAssert.isTrue(purchaseReturnOrder.getDownStreamCompanyId().equals(customerId), purchaseReturnOrder.getCode() + "，单据归属错误！");

    if (isUpdata) {
      if (purchaseReturnOrder.getReturnOrdState() != DownPurchaseReturnOrderEnums.OrdState.CONFIRM.getStatus()
              && purchaseReturnOrder.getReturnOrdState() != DownPurchaseReturnOrderEnums.OrdState.STATEMENT.getStatus() ) {
        throw new BusinessException(purchaseReturnOrder.getCode() + "，单据未在确认状态或未生成对账单！");
      }
    }
    else {
      if (purchaseReturnOrder.getReturnOrdState() != DownPurchaseReturnOrderEnums.OrdState.CONFIRM.getStatus()) {
        throw new BusinessException(purchaseReturnOrder.getCode() + "，单据未在确认状态！");
      }
      if (purchaseReturnOrder.getStatementId() != null) {
        throw new BusinessException(purchaseReturnOrder.getCode() + "，单据已经生成对账单！");
      }
    }
    if (!purchaseReturnOrder.getCode().equals(this.sourceCode)) {
      throw new IllegalParameterException("单据编号与id无法对齐");
    }
    return purchaseReturnOrder;
  }

  /**
   * 处理费用单
   * @param customerId
   * @param isUpdata
   * @return
   */
  private DownCostBill getCostBill(Long customerId, boolean isUpdata) {
    ExtAssert.isTrue(this.sourceType == DownStatementAccountBillEnum.SOURCE_COST_BILL.getStatus(), "类型错误");
    DownCostBillReadRepository costBillReadRepository = (DownCostBillReadRepository) SpringContextUtils.getBean(DownCostBillRepository.class);
    DownCostBill costBill = costBillReadRepository.getById(this.sourceId);

    ExtAssert.isTrue(costBill.getCustomerId().equals(customerId), costBill.getCode() + "，单据归属错误！");

    if (isUpdata) {
      if (costBill.getState() != DownCostBillEnum.CONFIRM.getStatus()
              && costBill.getState() != DownCostBillEnum.STATEMENT.getStatus() ) {
        throw new BusinessException(costBill.getCode() + "，单据未在确认状态或未生成对账单！");
      }
    }
    else {
      if (costBill.getState() != DownCostBillEnum.CONFIRM.getStatus()) {
        throw new BusinessException(costBill.getCode() + "，单据未在确认状态！");
      }
      if (costBill.getStatementOfAccountId() != null) {
        throw new BusinessException(costBill.getCode() + "，单据已经生成对账单！");
      }
    }

    if (!costBill.getCode().equals(this.sourceCode)) {
      throw new IllegalParameterException("单据编号与id无法对齐");
    }
    if (costBill.getConfirmState() != DownCostBillEnum.OTHERPARTY_CONFIRM.getStatus()) {
      throw new BusinessException(costBill.getCode() + "，对方仍未确认费用单有效");
    }
    return costBill;
  }

  /**
   * 处理收入单
   * @param customerId
   * @param isUpdata
   * @return
   */
  private DownIncomeBill getIncomeBill(Long customerId, boolean isUpdata) {
    ExtAssert.isTrue(this.sourceType == DownStatementAccountBillEnum.SOURCE_INCOME_BILL.getStatus(), "类型错误");
    DownIncomeBillReadRepository incomeBillReadRepository = (DownIncomeBillReadRepository) SpringContextUtils.getBean(DownIncomeBillRepository.class);
    DownIncomeBill incomeBill = incomeBillReadRepository.getById(this.sourceId);

    ExtAssert.isTrue(incomeBill.getCustomerId().equals(customerId), incomeBill.getCode() + "，单据归属错误！");

    if (isUpdata) {
      if (incomeBill.getState() != DownIncomeBillEnum.CONFIRM.getStatus()
              && incomeBill.getState() != DownIncomeBillEnum.STATEMENT.getStatus() ) {
        throw new BusinessException(incomeBill.getCode() + "，单据未在确认状态或未生成对账单！");
      }
    }
    else {
      if (incomeBill.getState() != DownIncomeBillEnum.CONFIRM.getStatus()) {
        throw new BusinessException(incomeBill.getCode() + "，单据未在确认状态！");
      }
      if (incomeBill.getStatementOfAccountId() != null) {
        throw new BusinessException(incomeBill.getCode() + "，单据已经生成对账单！");
      }
    }

    if (!incomeBill.getCode().equals(this.sourceCode)) {
      throw new IllegalParameterException("单据编号与id无法对齐");
    }
    if (incomeBill.getConfirmState() != DownIncomeBillEnum.OTHERPARTY_CONFIRM.getStatus()) {
      throw new BusinessException(incomeBill.getCode() + "，对方仍未确认费用单有效");
    }
    return incomeBill;
  }

  /**
   * 对账单id
   */
  private Long statementAccountBillId;
  /**
   * 来源单类型 0 销售单 1 销售退货单 2采购单 4 采购退货单 5 费用单 6 收入单
   */
  private Short sourceType;
  /**
   * 来源单号
   */
  private String sourceCode;
  /**
   * 来源单id
   */
  private Long sourceId;
  /**
   * 单据总额
   */
  private BigDecimal totalAmount;
}
